import os
import subprocess
from datetime import datetime
import av
import cv2
from queue import Queue
import time
from config import FPS, IMG_SIZE

queue = None
target_method = None

stop_list = []
live_list = []


def flush_target_m3u8(raw_m3u8_path, target_m3u8_path, last_line, target_m3u8, timeDay, http_m3u8_path, log):
    global live_list
    target = target_m3u8
    last = last_line
    index = 0
    stop_flag = False
    while not stop_flag:
        if stop_flag:
            log.info(f"标注位关闭线程:{http_m3u8_path}")
            break
        if stop_flag:
            1 / 0
        try:
            if http_m3u8_path in stop_list:
                #     log.info(f"存活列表长度:{len(live_list)},待关闭地址:{http_m3u8_path}")
                #     # print("需要关闭列表", stop_list, "待关闭地址", http_m3u8_path)
                #     # print(http_m3u8_path, "线程退出")
                stop_flag = True
                stop_list.remove(http_m3u8_path)
                log.info(f"强制关闭线程:{http_m3u8_path}")
                break
            with open(raw_m3u8_path, "r", encoding="utf-8") as file_log:
                flag = False
                while True:
                    line = file_log.readline().strip()  # 读取文件中的数据
                    if line:
                        if flag:
                            # print("写入最新数据", line)

                            if timeDay in line and line[-2:] == "ts":
                                target.append(line)
                                target = target[:6] + target[8:]
                                # print("删除数据", target[6:8])
                                last = line
                            if timeDay not in line:
                                target.append(line)

                        if last == line:
                            flag = True
                    else:
                        break
            target[5] = '#EXT-X-MEDIA-SEQUENCE:' + target[7].split("_")[1][:-3]
            content = ''.join(f"{line}\n" if i < len(target) - 1 else line for i, line in enumerate(target))
            with open(target_m3u8_path, "w", encoding="utf-8") as f:
                f.write(content)
            # # print("更新长度为", len(target))
            # with open(target_m3u8_path, "w", encoding="utf-8") as f:
            #     for t in target:
            #         f.write(t + "\n")
            #         f.flush()
        except Exception as e:
            log.info(str(e))
            break
        finally:
            time.sleep(0.5)
            # print(time.time())


def get_target_mp4(folder_path, target_time, timeDay):
    target_file = None
    files = os.listdir(folder_path)
    # 按照文件创建时间进行排序
    sorted_files = sorted(
        [file for file in files if os.path.isfile(os.path.join(folder_path, file)) and file.endswith('.mp4')],
        key=lambda x: os.path.getctime(os.path.join(folder_path, x)))
    # sorted_files = sorted(sorted_files, key=int)
    # print(sorted_files)
    if len(sorted_files) == 1:
        t_file = timeDay + " " + sorted_files[0].split(".")[0][:-2]
        t_obj = datetime.strptime(t_file, "%Y-%m-%d %H-%M-%S")
        t_timestamp = int(t_obj.timestamp())
        if float(t_timestamp) < float(target_time):
            target_file = sorted_files[0]
    else:
        for i in range(len(sorted_files) - 1):
            t_file = timeDay + " " + sorted_files[i].split(".")[0][:-2]
            n_file = timeDay + " " + sorted_files[i + 1].split(".")[0][:-2]
            t_obj = datetime.strptime(t_file, "%Y-%m-%d %H-%M-%S")
            t_timestamp = int(t_obj.timestamp())
            n_obj = datetime.strptime(n_file, "%Y-%m-%d %H-%M-%S")
            n_timestamp = int(n_obj.timestamp())
            # print(float(t_timestamp), float(target_time), float(n_timestamp))
            if float(t_timestamp) < float(target_time) < float(n_timestamp):
                # print(float(t_timestamp), float(target_time), float(n_timestamp))
                target_file = sorted_files[i]
        # print("target_file", target_file)
        if not target_file:
            t_file = timeDay + " " + sorted_files[len(sorted_files) - 1].split(".")[0][:-2]
            t_obj = datetime.strptime(t_file, "%Y-%m-%d %H-%M-%S")
            t_timestamp = int(t_obj.timestamp())
            if float(t_timestamp) < float(target_time):
                target_file = sorted_files[len(sorted_files) - 1]
    # 如果只有一个文件夹，那么前一个文件夹为空
    return target_file, sorted_files[sorted_files.index(target_file) + 1:]


def save_img(target_index, file_path, nginx_path):
    """
        基于av库生成取证图片
        :param target_index: 取证时间在目标二进制文件的索引位置
        :param file_path: 目标二进制文件路径
        :param nginx_path: 设置取证图片nginx代理路径
        :return: result：保存成功后取证图片nginx代理路径
    """
    with open(file_path, 'rb') as file:
        data = file.read()  # 读取文件中的数据

    selfcodec = av.CodecContext.create('hevc', 'r')
    packets = selfcodec.parse(data)
    if len(packets) == 0:
        selfcodec = av.CodecContext.create('h264', 'r')
        packets = selfcodec.parse(data)

    count = 0
    target_packet = packets[target_index + 3]
    if target_index > 10:
        packets = packets[target_index - 6:target_index + 4]
    else:
        packets = packets[0:target_index + 1]
    for packet in packets:
        try:
            frames = selfcodec.decode(packet)
        except Exception as e:
            print(str(e))
            count += 1
            continue
        for frame in frames:
            img_data = frame.to_ndarray(format='bgr24')
            if len(img_data) > 0:
                if count == len(packets) - 1:
                    print(target_packet == packet)
                    img = nginx_path
                    # leftUpX = 126
                    # leftUpY = 28
                    # rightDownX = 146
                    # rightDownY = 56
                    # # 在图片上画绿色框
                    # cv2.rectangle(img_data, (leftUpX, leftUpY), (rightDownX, rightDownY), (0, 255, 0), 2)
                    cv2.imwrite(img, img_data)
                    return img
                count += 1
    return ""


def save_img_two_file(target_index, file_path, before_file_path, nginx_path):
    """
           基于av库生成取证图片
           :param target_index: 取证时间在目标二进制文件的索引位置
           :param file_path: 目标二进制文件路径
           :param before_file_path: 目标二进制文件前一个文件路径
           :param nginx_path: 设置取证图片nginx代理路径
           :return: result：保存成功后取证图片nginx代理路径
   """
    with open(file_path, 'rb') as file:
        data = file.read()  # 读取文件中的数据
    selfcodec = av.CodecContext.create('hevc', 'r')
    packets = selfcodec.parse(data)
    if len(packets) == 0:
        selfcodec = av.CodecContext.create('h264', 'r')
        packets = selfcodec.parse(data)
    count = 0
    target_packet = packets[target_index + 3]
    packets = packets[0:target_index + 4]
    with open(before_file_path, 'rb') as file:
        before_data = file.read()  # 读取文件中的数据
    before_packets = selfcodec.parse(before_data)
    before_packets = before_packets[-7:]
    packets = before_packets + packets
    for packet in packets:
        try:
            frames = selfcodec.decode(packet)
        except Exception as e:
            count += 1
            continue
        for frame in frames:
            img_data = frame.to_ndarray(format='bgr24')
            if len(img_data) > 0:
                if count == len(packets) - 1:
                    img = nginx_path
                    # leftUpX = 126
                    # leftUpY = 28
                    # rightDownX = 146
                    # rightDownY = 56
                    # # 在图片上画绿色框
                    # cv2.rectangle(img_data, (leftUpX, leftUpY), (rightDownX, rightDownY), (0, 255, 0), 2)
                    cv2.imwrite(img, img_data)
                    return img
                count += 1
    return ""


def save_video(start_closest_index, end_closest_index, folder_path, nginx_path):
    """
            基于av库和ffmpeg生成取证短视频
            :param folder_path: 二进制文件路径
            :param start_closest_index: 取证13位毫秒级开始时间戳索引
            :param end_closest_index: 取证13位毫秒级结束时间戳索引位置
            :param nginx_path: 设置取证图片nginx代理路径
            :return: 保存成功后取证视频nginx代理路径
    """
    with open(folder_path, 'rb') as file:
        data = file.read()  # 读取文件中的数据
    selfcodec = av.CodecContext.create('h264', 'r')
    packets = selfcodec.parse(data)
    # print(packets)
    count = 0
    # # print(packets)
    # print("2",len(packets))
    img_size = None
    for packet in packets:
        try:
            frames = selfcodec.decode(packet)
        except Exception as e:
            # print(str(e))
            count += 1
            continue
        if len(frames) > 0:
            for frame in frames:
                img_data = frame.to_ndarray(format='bgr24')
                # print("img_data",img_data.shape[0],img_data.shape[1])
                img_size = (img_data.shape[1], img_data.shape[0])
            if img_size is not None:
                break

    # packets = packets[start_closest_index + 4:end_closest_index + 4]
    packets = packets[start_closest_index - 6:end_closest_index + 4]
    # frames = selfcodec.decode(target_packet)

    output_file = nginx_path
    # 设置视频编解码器和输出帧率
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    # 创建VideoWriter对象
    if img_size is None:
        img_size = IMG_SIZE
    # print("img_size", img_size)
    out = cv2.VideoWriter(output_file, fourcc, FPS, img_size)
    print("包长度",len(packets))
    del_frame = 0
    for packet in packets:
        try:
            del_frame += 1
            frames = selfcodec.decode(packet)
        except Exception as e:
            print("+++++++++++++" + str(e))
            count += 1
            continue
        if del_frame > 10:
            for frame in frames:
                img_data = frame.to_ndarray(format='bgr24')
                if len(img_data) > 0:
                    out.write(img_data)

    out.release()
    subprocess.call(
        ['ffmpeg', '-i', output_file, '-c:v', 'libx264', '-preset', 'slow',
         output_file[:-4] + "copy" + output_file[-4:]])
    return output_file[:-4] + "copy" + output_file[-4:]


def save_video_two_file(start_closest_index, end_closest_index, folder_path, before_folder_path, nginx_path):
    """
    基于av库和ffmpeg生成取证短视频
    :param folder_path: 目标二进制文件路径
    :param before_folder_path: 目标二进制文件前一个文件路径
    :param start_closest_index: 取证13位毫秒级开始时间戳索引
    :param end_closest_index: 取证13位毫秒级结束时间戳索引位置
    :param nginx_path: 设置取证图片nginx代理路径
    :return: 保存成功后取证视频nginx代理路径
    """
    with open(folder_path, 'rb') as file:
        data = file.read()  # 读取文件中的数据
    with open(before_folder_path, 'rb') as file:
        before_data = file.read()  # 读取文件中的数据
    selfcodec = av.CodecContext.create('h264', 'r')
    packets = selfcodec.parse(data)
    before_packets = selfcodec.parse(before_data)
    count = 0
    packets = packets[0:end_closest_index + 4]
    before_packets = before_packets[start_closest_index + 4:]
    packets = before_packets + packets
    img_size = None
    for packet in packets:
        try:
            frames = selfcodec.decode(packet)
        except Exception as e:
            # print(str(e))
            count += 1
            continue
        if len(frames) > 0:
            for frame in frames:
                img_data = frame.to_ndarray(format='bgr24')
                # print("img_data",img_data.shape[0],img_data.shape[1])
                img_size = (img_data.shape[1], img_data.shape[0])
            if img_size is not None:
                break
    output_file = nginx_path
    # 设置视频编解码器和输出帧率
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    if img_size is None:
        img_size = IMG_SIZE
    out = cv2.VideoWriter(output_file, fourcc, FPS, img_size)
    for packet in packets:
        try:
            frames = selfcodec.decode(packet)
        except Exception as e:
            count += 1
            continue
        for frame in frames:
            img_data = frame.to_ndarray(format='bgr24')
            if len(img_data) > 0:
                out.write(img_data)
    out.release()
    subprocess.call(
        ['/ZLMVideoReader/ZLMVideoReader/ffmpeg/ffmpeg', '-i', output_file, '-c:v', 'libx264', '-preset', 'slow',
         output_file[:-4] + "copy" + output_file[-4:]])
    return output_file[:-4] + "copy" + output_file[-4:]


def get_target_file(folder_path, target_time):
    """
    根据传入的时间日期和13位毫秒级时间戳，确定取证时间所在的目标二进制文件及目标二进制文件前一个二进制文件
    获取前一个二进制文件的目的是因为如果取证时间所在的视频帧在目标文件的前几帧率，且里面没有I帧，无法成功
    生成图片，需要参数目标二进制文件前一个二进制文件中与之时间连续的I帧，保证图片成功生成
    :param folder_path: 二进制文件路径
    :param target_time: 取证13位毫秒级时间戳
    :return: result：目标二进制文件及目标二进制文件前一个二进制文件
    """
    target_file = None
    files = os.listdir(folder_path)
    # 按照文件创建时间进行排序
    sorted_files = sorted(
        [file for file in files if os.path.isfile(os.path.join(folder_path, file)) and not os.path.splitext(file)[1]],
        key=lambda x: os.path.getctime(os.path.join(folder_path, x)))
    sorted_files = sorted(sorted_files, key=int)
    if len(sorted_files) == 1:
        if float(sorted_files[0]) < float(target_time):
            target_file = sorted_files[0]
    else:
        for i in range(len(sorted_files) - 1):
            if float(sorted_files[i]) < float(target_time) < float(sorted_files[i + 1]):
                target_file = sorted_files[i]
        if not target_file:
            if float(sorted_files[len(sorted_files) - 1]) < float(target_time):
                target_file = sorted_files[len(sorted_files) - 1]
    # 如果只有一个文件，那么前一个文件为空
    return target_file, sorted_files[sorted_files.index(target_file) - 1]


def get_target_file_stream(folder_path, target_time):
    target_file = None
    files = os.listdir(folder_path)
    # 按照文件创建时间进行排序
    sorted_files = sorted(
        [file for file in files if os.path.isfile(os.path.join(folder_path, file)) and not os.path.splitext(file)[1]],
        key=lambda x: os.path.getctime(os.path.join(folder_path, x)))
    sorted_files = sorted(sorted_files, key=int)
    # print(sorted_files)
    if len(sorted_files) == 1:
        if float(sorted_files[0]) < float(target_time):
            target_file = sorted_files[0]
    else:
        for i in range(len(sorted_files) - 1):
            if float(sorted_files[i]) < float(target_time) < float(sorted_files[i + 1]):
                target_file = sorted_files[i]
        if not target_file:
            if float(sorted_files[len(sorted_files) - 1]) < float(target_time):
                target_file = sorted_files[len(sorted_files) - 1]
    # 如果只有一个文件夹，那么前一个文件夹为空
    return target_file, sorted_files[sorted_files.index(target_file) + 1:]


def get_closest_index(folder_path, target_file, target_time):
    """
        根据13位毫秒级时间戳确定取证时间在目标文件中的索引位置
        :param folder_path: 二进制文件路径
        :param target_time: 目标文件
        :param target_time: 取证13位毫秒级时间戳
        :return: 取证时间在目标文件中的索引位置
        """
    time_list = []
    with open(folder_path + "/" + target_file + '.log', encoding="utf-8") as file_log:
        while True:
            line = file_log.readline().strip()  # 读取文件中的数据
            if line:

                time_list.append(int(line))
            else:
                break

    given_timestamp_int = int(target_time)
    min_diff = float('inf')
    closest_timestamp = None
    for timestamp in time_list:
        timestamp_int = int(timestamp)
        diff = abs(timestamp_int - given_timestamp_int)
        if diff < min_diff:
            min_diff = diff
            closest_timestamp = timestamp
    if closest_timestamp is not None:
        if abs(closest_timestamp - given_timestamp_int) > 300:
            return None
        return time_list.index(closest_timestamp)
    else:
        return None


def get_time_data(target_file_path, index, timeDiff):
    global queue, target_method
    selfcodec = av.CodecContext.create('hevc', 'r')
    i = index
    last_position = 0
    while True:
        # 实时
        if target_method != index:
            # print("历史存储线程关闭")
            queue = Queue(maxsize=timeDiff * 10)
            break
        with open(target_file_path, "rb") as file:
            file.seek(last_position)
            new_data = file.read()
            # print("读取数据中！！！")
            if new_data:
                packets = selfcodec.parse(new_data)
                if i != -1:
                    packets = packets[index:]
                    i = -1
                for packet in packets:
                    try:
                        frames = selfcodec.decode(packet)
                        # print(frames)
                        if queue.qsize() == queue.maxsize:
                            queue.get()
                        queue.put(frames)
                        last_position = file.tell()
                    except Exception as e:
                        print("+++++++++++++" + str(e))
                        continue

        time.sleep(0.05)


def get_closest_img(folder_path, target_time, nginx_path):
    """
    生成取证图片
    :param folder_path: 二进制文件路径
    :param target_time: 取证13位毫秒级时间戳
    :param nginx_path: 设置取证图片nginx代理路径
    :return: result：保存成功后取证图片nginx代理路径
    """
    target_file, before_file = get_target_file(folder_path, target_time)
    if not target_file:
        return "二进制文件不存在，请确认是否开启视频录制"
    closest_index = get_closest_index(folder_path, target_file, target_time)
    if closest_index is None:
        return "传入的时间戳不在二进制文件范围内，请确认传入时间戳是否正确"
    if closest_index < 10:
        nginx_img_path = save_img_two_file(closest_index, folder_path + "/" + target_file,
                                           folder_path + "/" + before_file, nginx_path)
        return nginx_img_path
    else:
        nginx_img_path = save_img(closest_index, folder_path + "/" + target_file, nginx_path)
        return nginx_img_path


def get_closest_video(folder_path, startTimeStamp, endTimeStamp, nginx_path, log):
    """
        生成取证短视频
        :param folder_path: 二进制文件路径
        :param startTimeStamp: 取证13位毫秒级开始时间戳
        :param endTimeStamp: 取证13位毫秒级结束时间戳
        :param nginx_path: 设置取证图片nginx代理路径
        :param log: 日志
        :return: result：保存成功后取证图片nginx代理路径
    """
    try:
        start_target_file, _ = get_target_file(folder_path, startTimeStamp)
        end_target_file, _ = get_target_file(folder_path, endTimeStamp)
        if not start_target_file or not end_target_file:
            return ""
        if start_target_file == end_target_file:
            start_closest_index = get_closest_index(folder_path, start_target_file, startTimeStamp)
            end_closest_index = get_closest_index(folder_path, end_target_file, endTimeStamp)
            nginx_video_path = save_video(start_closest_index, end_closest_index, folder_path + "/" + start_target_file,
                                          nginx_path)
            return nginx_video_path
        else:
            start_closest_index = get_closest_index(folder_path, start_target_file, startTimeStamp)
            end_closest_index = get_closest_index(folder_path, end_target_file, endTimeStamp)
            nginx_video_path = save_video_two_file(start_closest_index, end_closest_index,
                                                   folder_path + "/" + start_target_file,
                                                   folder_path + "/" + end_target_file,
                                                   nginx_path)
            return nginx_video_path
    except Exception as e:
        log.error(f"读取视频报错{e}")
    finally:
        return ""


if __name__ == '__main__':
    save_video(80, 120, r'C:\Users\xinyingjie\Downloads\1740559033193', './test.mp4')
